package workqueue

import (
	"sync"
	"time"
)

// 任务状态
const (
	Unknown    = iota
	Waiting    //等待中
	Processing //进行中
	Success    //处理完成
	Failure    //处理失败
	Expired    //超时过期
)

// Work 一个工作
type Work struct {
	Type   string      //任务类型 根据该字段调用对应的处理器
	Matter interface{} //任务要处理的课题
	ID     string      //任务ID
	State  int         //任务状态
	Close  bool        //是否关闭
}

// WorkPool 工作任务池子
type WorkPool struct {
	workList sync.Map
}

// Len 查看长度
func (wp *WorkPool) Len() int {
	len := 0
	wp.workList.Range(func(key, value interface{}) bool {
		len++
		return true
	})
	return len
}

// Worker 一个任务处理者
type Worker interface {
	// Async() bool       //是否支持并发
	Type() string             // 注册处理的类型
	Handle(Work, func(*Work)) //处理方法 返回处理过后的work
}

// WorkerPool 工作池子
type WorkerPool struct {
	workerList sync.Map
}

// Len 查看长度
func (wp *WorkerPool) Len() int {
	len := 0
	wp.workerList.Range(func(key, value interface{}) bool {
		len++
		return true
	})
	return len
}

var workPool WorkPool
var workerPool WorkerPool

func init() {
	workPool = WorkPool{}
	workerPool = WorkerPool{}
	go AssemblyLine()
}

// RegisterWorker 注册一个工作者
func RegisterWorker(w Worker) {
	workerPool.workerList.Store(w.Type(), w)
}

// Push 推进一个任务
func Push(w Work) string {
	if Exist(w.ID) {
		workPool.workList.Store(w.ID, w)
	} else {
		w.State = Waiting
		workPool.workList.Store(w.ID, w)
	}

	return w.ID
}

// Pull 拉取任务
func Pull(id string) (w Work, ok bool) {
	value, ok := workPool.workList.Load(id)
	if ok {
		return value.(Work), true
	}
	return Work{}, false
}

// Close 关闭一个任务
func Close(id string) bool {
	if w, ok := Pull(id); ok {
		w.Close = true
		Push(w)
		return true
	}
	return false
}

// Delete 删除一个任务
func Delete(id string) {
	workPool.workList.Delete(id)
}

// Probe 探测任务最新的状态
func Probe(id string) int {
	if w, ok := Pull(id); ok {
		return w.State
	}
	return Unknown
}

// Exist 查看对象是否存在
func Exist(id string) bool {
	if _, ok := Pull(id); ok {
		return true
	}
	return false
}

// AssemblyLine 处理流水线
func AssemblyLine() {
	for {
		workPool.workList.Range(func(_, value interface{}) bool {
			work := value.(Work)
			if work.State == Waiting {
				//获取对应的处理器
				wr, ok := workerPool.workerList.Load(work.Type)
				if ok {
					//获取成功
					work.State = Processing
					Push(work)
					worker := wr.(Worker)
					//调用对应的方法
					go worker.Handle(work, func(w *Work) {
						Push(*w)
					})
				}
			}
			return true
		})
		time.Sleep(time.Second * 5)
	}
}
